﻿#include "../../includes/3d/cmy3dwidget.h"
#include "../../includes/3d/stb_image.h"
#include "../../includes/QsLog/QsLog.h"
#include "../../includes/common/common.h"
#include "../../includes/common/NedAllocatorImpl.h"

//#include <qDebug>
#include <QKeyEvent>
#include <QDesktopWidget>
#include <QPainter>
#include <QFileInfo>
#include <QDateTime>
#include <QFile>

CBaseNode::CBaseNode(QString name)
    : sceneManager(NULL),
      nodeName(name),
      nodeVisible(true),
      nodeEnable(true)
{
    m_VAO=m_VBO=m_EBO=0;
}

CBaseNode::~CBaseNode()
{
    deleteAllSubNodes();

    sceneManager->glDeleteVertexArrays(1, &m_VAO);
    sceneManager->glDeleteBuffers(1, &m_VBO);
    sceneManager->glDeleteBuffers(1, &m_EBO);
}

/**
 * @brief CBaseNode::addSubNode 添加一个子结点到当前结点中
 * @param node
 * @param direction 方向：0-前面，1-后面
 * @return
 */
bool CBaseNode::addSubNode(CBaseNode *node,int direction)
{
    if(isSubNodeExist(node))
        return false;

    if(direction == 0) subnodes.push_front(node);
    else subnodes.push_back(node);

    return true;
}

/**
 * @brief CBaseNode::isSubNodeExist 查找当前结点中是否存在指定的结点
 * @param node
 * @return
 */
bool CBaseNode::isSubNodeExist(CBaseNode *node)
{
    QList<CBaseNode*>::iterator iter = qFind(subnodes.begin(),subnodes.end(),node);
    if(iter != subnodes.end())
        return true;

    return false;
}

/**
 * @brief CBaseNode::getSubNode 得到指定名称的结点
 * @return
 */
CBaseNode* CBaseNode::getSubNode(QString nodeName)
{
    QList<CBaseNode*>::iterator iter = subnodes.begin();
    for(;iter != subnodes.end();++iter)
    {
        if((*iter)->getName() != nodeName)
            continue;

        return (*iter);
    }

    return NULL;
}

/**
 * @brief CBaseNode::deleteSubNode 删除指定结点
 * @param node
 * @return
 */
bool CBaseNode::deleteSubNode(CBaseNode *node)
{
    if(node == NULL || !isSubNodeExist(node))
        return false;

    QList<CBaseNode*>::iterator iter = qFind(subnodes.begin(),subnodes.end(),node);
    if(iter != subnodes.end())
    {
        delete (*iter);
        subnodes.erase(iter);

        return true;
    }

    return false;
}

/**
 * @brief CBaseNode::deleteAllSubNodes 删除所有的结点
 */
void CBaseNode::deleteAllSubNodes(void)
{
    QList<CBaseNode*>::iterator iter = subnodes.begin();
    for(;iter != subnodes.end();++iter)
        delete (*iter);

    subnodes.clear();
}

/**
 * @brief CBaseNode::init 初始化
 */
void CBaseNode::init(void)
{

}

/**
 * @brief CBaseNode::draw 绘制
 */
void CBaseNode::draw(void)
{
    if(!isVisible()) return;

    QList<CBaseNode*>::iterator iter = subnodes.begin();
    for(;iter != subnodes.end();++iter)
    {
        (*iter)->draw();
    }
}

/**
 * @brief CBaseNode::onProcessMouseEvent 处理鼠标事件
 * @param event
 * @return
 */
bool CBaseNode::onProcessMouseEvent(QMouseEvent *event)
{
    if(!isEnable()) return false;

    QList<CBaseNode*>::iterator iter = subnodes.begin();
    for(;iter != subnodes.end();++iter)
    {
        (*iter)->onProcessMouseEvent(event);
    }

    return true;
}

/**
 * @brief CBaseNode::onProcessWheelEvent 处理鼠标滚轮事件
 * @param event
 */
void CBaseNode::onProcessWheelEvent(QWheelEvent *event)
{
    if(!isEnable()) return;

    QList<CBaseNode*>::iterator iter = subnodes.begin();
    for(;iter != subnodes.end();++iter)
    {
        (*iter)->onProcessWheelEvent(event);
    }
}

/**
 * @brief CBaseNode::onProcessKeyEvent 处理键盘事件
 * @param event
 */
void CBaseNode::onProcessKeyEvent(QKeyEvent *event)
{
    if(!isEnable()) return;

    QList<CBaseNode*>::iterator iter = subnodes.begin();
    for(;iter != subnodes.end();++iter)
    {
        (*iter)->onProcessKeyEvent(event);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////

CCamera::CCamera(glm::vec3 position, glm::vec3 up, float yaw, float pitch)
    : Front(glm::vec3(0.0f, 0.0f, -1.0f)),
      MovementSpeed(SPEED),
      MouseSensitivity(SENSITIVITY),
      Zoom(ZOOM)
{
    m_firstMouse = true;
    Position = position;
    WorldUp = up;
    Yaw = yaw;
    Pitch = pitch;
    updateCameraVectors();
}

CCamera::CCamera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch)
    : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
    m_firstMouse = true;
    Position = glm::vec3(posX, posY, posZ);
    WorldUp = glm::vec3(upX, upY, upZ);
    Yaw = yaw;
    Pitch = pitch;
    updateCameraVectors();
}

CCamera::~CCamera()
{

}

glm::mat4 CCamera::GetViewMatrix()
{
    return glm::lookAt(Position, Position + Front, Up);
}

void CCamera::updateCameraVectors()
{
    glm::vec3 front;
    front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
    front.y = sin(glm::radians(Pitch));
    front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
    Front = glm::normalize(front);
    Right = glm::normalize(glm::cross(Front, WorldUp));
    Up    = glm::normalize(glm::cross(Right, Front));
}

/**
 * @brief CCamera::onProcessMouseEvent 处理鼠标事件
 * @param event
 * @return
 */
void CCamera::onProcessMouseEvent(QMouseEvent *event)
{
    if(m_firstMouse)
    {
        m_lastMousePos = event->pos();
        m_firstMouse = false;
    }

    QPointF offset;
    offset.setX((float)(event->pos().x() - m_lastMousePos.x()));
    offset.setY((float)(m_lastMousePos.y() - event->pos().y()));
    m_lastMousePos = event->pos();

    offset.setX(offset.x() * MouseSensitivity);
    offset.setY(offset.y() * MouseSensitivity);

    Yaw   += offset.x();
    Pitch += offset.y();

    if (Pitch > 89.0f)
        Pitch = 89.0f;
    if (Pitch < -89.0f)
        Pitch = -89.0f;

    updateCameraVectors();
}

/**
 * @brief CCamera::onProcessWheelEvent 处理鼠标滚轮事件
 * @param event
 */
void CCamera::onProcessWheelEvent(QWheelEvent *event)
{
    Zoom -= (event->delta() > 0 ? 1.0f : -1.0f);;
    if (Zoom < 1.0f)
        Zoom = 1.0f;
    if (Zoom > 45.0f)
        Zoom = 45.0f;
}

/**
 * @brief CCamera::onProcessKeyEvent 处理键盘事件
 * @param event
 */
void CCamera::onProcessKeyEvent(QKeyEvent *event,float deltaTime)
{
    float velocity = MovementSpeed * deltaTime;
    switch(event->key())
    {
    case Qt::Key_Up:
    {
        Position += Front * velocity;
    }
        break;
    case Qt::Key_Down:
    {
        Position -= Front * velocity;
    }
        break;
    case Qt::Key_Left:
    {
        Position -= Right * velocity;
    }
        break;
    case Qt::Key_Right:
    {
        Position += Right * velocity;
    }
        break;
    default:
        break;
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////

CSceneManager::CSceneManager(QWidget *parent,
                         QString caption,
                         int screenWidth,int screenHeight,bool isfullscreen)
    : QOpenGLWidget(parent)
{
    this->setFocusPolicy(Qt::ClickFocus);
    this->setMouseTracking(true);

    installEventFilter(this);

    m_deltaTime=0.0f;
    m_lastTime=0;

    if(caption != "")
        this->setWindowTitle(caption);

    if(screenWidth > 0 && screenHeight > 0)
    {
        this->setGeometry( 0, 0, screenWidth, screenHeight );

        this->move((QApplication::desktop()->width() - this->width()) / 2,
                   (QApplication::desktop()->height() - this->height()) / 2);
    }

    if(isfullscreen)
        this->showFullScreen();
}

CSceneManager::~CSceneManager()
{
    deleteShader();
    deleteTexture();
    deleteAllNodes();
}

/**
 * @brief CSceneManager::setScreenSize 设置屏幕高宽
 * @param size
 */
void CSceneManager::setScreenSize(QSize size)
{
    if(size.isValid() && size != m_screenSize)
    {
        this->setGeometry( 0, 0, size.width(), size.height() );
    }

    m_screenSize = size;
}

/**
 * @brief CSceneManager::setFullscreen 设置是否全屏
 * @param isfs
 */
void CSceneManager::setFullscreen(bool isfs)
{
    if(m_fullscreen == isfs)
        return;

    if(isfs)
    {
        this->showFullScreen();
    }
    else
    {
        this->showNormal();
        this->setGeometry( 0, 0, m_screenSize.width(), m_screenSize.height() );

        this->move((QApplication::desktop()->width() - this->width()) / 2,
                   (QApplication::desktop()->height() - this->height()) / 2);
    }

    m_fullscreen = isfs;
}

/**
 * @brief CSceneManager::loadShaderScript 导入shader脚本
 * @param vertexPath
 * @param fragmentPath
 * @return
 */
quint32 CSceneManager::loadShaderScript(QString vertexPath, QString fragmentPath)
{
    if(vertexPath == "" || fragmentPath == "")
        return 0;

    QFileInfo pvertexfileinfo(vertexPath);
    QFileInfo pfragmentfileinfo(fragmentPath);
    if(!pvertexfileinfo.exists() || !pfragmentfileinfo.exists())
        return 0;

    QString sharderMd5 = generateMd5(vertexPath+fragmentPath);
    QHash<QString,quint32>::iterator iter = m_sharderIds.find(sharderMd5);
    if(iter != m_sharderIds.end())
        return 0;

    const char* vShaderCode = NULL;
    const char* fShaderCode = NULL;

    QFile pvertexFile(vertexPath);
    if(pvertexFile.open(QIODevice::ReadOnly))
    {
        vShaderCode = pvertexFile.readAll().constData();
        pvertexFile.close();
    }

    QFile pfragmentFile(fragmentPath);
    if(pfragmentFile.open(QIODevice::ReadOnly))
    {
        fShaderCode = pfragmentFile.readAll().constData();
        pfragmentFile.close();
    }

    quint32 vertex, fragment;

    fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fShaderCode, NULL);
    glCompileShader(fragment);

    checkCompileErrors(fragment, "FRAGMENT");

    vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vShaderCode, NULL);
    glCompileShader(vertex);

    checkCompileErrors(vertex, "VERTEX");

    quint32 shaderProgramID = glCreateProgram();
    glAttachShader(shaderProgramID, vertex);
    glAttachShader(shaderProgramID, fragment);
    glLinkProgram(shaderProgramID);

    checkCompileErrors(shaderProgramID, "PROGRAM");

    glDeleteShader(vertex);
    glDeleteShader(fragment);

    m_sharderIds[sharderMd5] = shaderProgramID;

    return shaderProgramID;
}

void CSceneManager::setBool(qint32 sharderID,const QString &name, int valCount,...)
{
    if(valCount <= 0 || !isShaderExist(sharderID)) return;

    QVector<int> tmpValues;
    va_list ap;
    va_start(ap, valCount);
    for (int i = 0; i < valCount; i++)
    {
        bool value = va_arg(ap, bool);
        tmpValues.push_back((int)value);
    }
    va_end(ap);

    switch(valCount)
    {
    case 1:
    {
        glUniform1i(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0]);
    }
        break;
    case 2:
    {
        glUniform2i(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0],
                    tmpValues[1]);
    }
        break;
    case 3:
    {
        glUniform3i(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0],
                    tmpValues[1],
                    tmpValues[2]);
    }
        break;
    case 4:
    {
        glUniform4i(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0],
                    tmpValues[1],
                    tmpValues[2],
                    tmpValues[3]);
    }
        break;
    default:
        break;
    }
}

void CSceneManager::setInt(qint32 sharderID,const QString &name,int valCount,...)
{
    if(valCount <= 0 || !isShaderExist(sharderID)) return;

    QVector<int> tmpValues;
    va_list ap;
    va_start(ap, valCount);
    for (int i = 0; i < valCount; i++)
    {
        int value = va_arg(ap, int);
        tmpValues.push_back(value);
    }
    va_end(ap);

    switch(valCount)
    {
    case 1:
    {
        glUniform1i(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0]);
    }
        break;
    case 2:
    {
        glUniform2i(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0],
                    tmpValues[1]);
    }
        break;
    case 3:
    {
        glUniform3i(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0],
                    tmpValues[1],
                    tmpValues[2]);
    }
        break;
    case 4:
    {
        glUniform4i(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0],
                    tmpValues[1],
                    tmpValues[2],
                    tmpValues[3]);
    }
        break;
    default:
        break;
    }
}

void CSceneManager::setFloat(qint32 sharderID,const QString &name,int valCount,...)
{
    if(valCount <= 0 || !isShaderExist(sharderID)) return;

    QVector<float> tmpValues;
    va_list ap;
    va_start(ap, valCount);
    for (int i = 0; i < valCount; i++)
    {
        float value = va_arg(ap, float);
        tmpValues.push_back(value);
    }
    va_end(ap);

    switch(valCount)
    {
    case 1:
    {
        glUniform1f(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0]);
    }
        break;
    case 2:
    {
        glUniform2f(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0],
                    tmpValues[1]);
    }
        break;
    case 3:
    {
        glUniform3f(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0],
                    tmpValues[1],
                    tmpValues[2]);
    }
        break;
    case 4:
    {
        glUniform4f(glGetUniformLocation(sharderID, name.toStdString().c_str()),
                    tmpValues[0],
                    tmpValues[1],
                    tmpValues[2],
                    tmpValues[3]);
    }
        break;
    default:
        break;
    }
}

void CSceneManager::setVec2(qint32 sharderID,const QString &name, const glm::vec2 &value)
{
    if(!isShaderExist(sharderID)) return;

    glUniform2fv(glGetUniformLocation(sharderID, name.toStdString().c_str()), 1, &value[0]);
}

void CSceneManager::setVec2(qint32 sharderID,const QString &name, float x, float y)
{
    if(!isShaderExist(sharderID)) return;

    glUniform2f(glGetUniformLocation(sharderID, name.toStdString().c_str()), x, y);
}

void CSceneManager::setVec3(qint32 sharderID,const QString &name, const glm::vec3 &value)
{
    if(!isShaderExist(sharderID)) return;

    glUniform3fv(glGetUniformLocation(sharderID, name.toStdString().c_str()), 1, &value[0]);
}

void CSceneManager::setVec3(qint32 sharderID,const QString &name, float x, float y, float z)
{
    if(!isShaderExist(sharderID)) return;

    glUniform3f(glGetUniformLocation(sharderID, name.toStdString().c_str()), x, y, z);
}

void CSceneManager::setVec4(qint32 sharderID,const QString &name, const glm::vec4 &value)
{
    if(!isShaderExist(sharderID)) return;

    glUniform4fv(glGetUniformLocation(sharderID, name.toStdString().c_str()), 1, &value[0]);
}

void CSceneManager::setVec4(qint32 sharderID,const QString &name, float x, float y, float z, float w)
{
    if(!isShaderExist(sharderID)) return;

    glUniform4f(glGetUniformLocation(sharderID, name.toStdString().c_str()), x, y, z, w);
}

void CSceneManager::setMat2(qint32 sharderID,const QString &name, const glm::mat2 &mat)
{
    if(!isShaderExist(sharderID)) return;

    glUniformMatrix2fv(glGetUniformLocation(sharderID, name.toStdString().c_str()), 1, GL_FALSE, &mat[0][0]);
}

void CSceneManager::setMat3(qint32 sharderID,const QString &name, const glm::mat3 &mat)
{
    if(!isShaderExist(sharderID)) return;

    glUniformMatrix3fv(glGetUniformLocation(sharderID, name.toStdString().c_str()), 1, GL_FALSE, &mat[0][0]);
}

void CSceneManager::setMat4(qint32 sharderID,const QString &name,glm::mat4 value)
{
    if(!isShaderExist(sharderID)) return;

    unsigned int transformLoc = glGetUniformLocation(sharderID, name.toStdString().c_str());
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(value));
}

/**
 * @brief CSceneManager::checkCompileErrors shader脚本编译错误检测
 * @param shader
 * @param type
 */
void CSceneManager::checkCompileErrors(quint32 shader, QString type)
{
    int success;
    char infoLog[1024];
    if (type != "PROGRAM")
    {
        glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            glGetShaderInfoLog(shader, 1024, NULL, infoLog);
            qDebug() << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << ":" << infoLog;
            QLOG_ERROR() << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << ":" << infoLog;
        }
    }
    else
    {
        glGetProgramiv(shader, GL_LINK_STATUS, &success);
        if (!success)
        {
            glGetProgramInfoLog(shader, 1024, NULL, infoLog);
            qDebug() << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << ":" << infoLog;
            QLOG_ERROR() << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << ":" << infoLog;
        }
    }
}

/**
 * @brief CSceneManager::loadTexture 导入纹理图片
 * @param texturePath
 * @return
 */
quint32 CSceneManager::loadTexture(QString texturePath)
{
    if(texturePath == "")
        return 0;

    QHash<QString,quint32>::iterator iter = m_textureIds.find(texturePath);
    if(iter != m_textureIds.end())
        return 0;

    quint32 texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    // 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    stbi_set_flip_vertically_on_load(true);

    // 加载并生成纹理
    int width, height, nrChannels;
    unsigned char *data = stbi_load(texturePath.toStdString().c_str(), &width, &height, &nrChannels, 0);
    if (data)
    {
        if(texturePath.toLower().contains(".png"))
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        else
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        qDebug()<<"CMy3dWidget::loadTexture:"<<texturePath<<" failed.";
        QLOG_ERROR()<<"CMy3dWidget::loadTexture:"<<texturePath<<" failed.";
    }
    stbi_image_free(data);

    m_textureIds[texturePath] = texture;

    return texture;
}

/**
 * @brief CSceneManager::useTexture 使用纹理
 * @param layerid
 * @param textureid
 */
void CSceneManager::useTexture(int layerid,quint32 textureid)
{
    if(textureid < 0 || !isTextureExist(textureid))
        return;

    glActiveTexture(GL_TEXTURE0+layerid);
    glBindTexture(GL_TEXTURE_2D, textureid);
}

/**
 * @brief CSceneManager::useTextures 使用纹理
 * @param textureids
 */
void CSceneManager::useTextures(QVector<quint32> textureids)
{
    if(textureids.empty())
        return;

    for(int i=0;i<textureids.size();i++)
    {
        useTexture(i,textureids[i]);
    }
}

/**
 * @brief CSceneManager::deleteTexture 删除纹理
 * @param textureid
 */
void CSceneManager::deleteTexture(quint32 textureid)
{
    if(textureid > 0 && !isTextureExist(textureid))
        return;

    quint32 *texArray = NULL;
    int texArrayIndex = 0;

    if(textureid > 0)
        texArray = (quint32*)allocBytes(sizeof(quint32));
    else
        texArray = (quint32*)allocBytes(m_textureIds.size()*sizeof(quint32));

    QHash<QString,quint32>::iterator iter = m_textureIds.begin();
    for(;iter != m_textureIds.end();)
    {
        if(textureid > 0 && iter.value() != textureid)
        {
            ++iter;
            continue;
        }

        texArray[texArrayIndex++] = iter.value();
        iter = m_textureIds.erase(iter);
        break;
    }

    deallocBytes(texArray);
    glDeleteTextures(texArrayIndex,texArray);
}

/**
 * @brief CSceneManager::isTextureExist 检测指定ID的纹理是否存在
 * @param textureid
 * @return
 */
bool CSceneManager::isTextureExist(quint32 textureid)
{
    if(textureid <= 0) return false;

    QHash<QString,quint32>::iterator iter = m_textureIds.begin();
    for(;iter != m_textureIds.end();++iter)
    {
        if(iter.value() == textureid)
            return true;
    }

    return false;
}

/**
 * @brief CSceneManager::getViewMatrix 得到摄像机矩阵
 * @return
 */
glm::mat4 CSceneManager::getViewMatrix(void)
{
    return mainCamera.GetViewMatrix();
}

/**
 * @brief CSceneManager::getProjectionMatrix 得到投影矩阵
 * @param fov
 * @return
 */
glm::mat4 CSceneManager::getProjectionMatrix()
{
    return glm::perspective(glm::radians(this->getCamera()->Zoom),
                                  (float)this->size().width() / (float)this->size().height(),
                                  0.1f,
                                  100.0f);
}

/**
 * @brief CSceneManager::isShaderExist 检测指定ID的shader是否存在
 * @param shaderid
 * @return
 */
bool CSceneManager::isShaderExist(quint32 shaderid)
{
    if(shaderid <= 0) return false;

    QHash<QString,quint32>::iterator iter = m_sharderIds.begin();
    for(;iter != m_sharderIds.end();++iter)
    {
        if(iter.value() == shaderid)
            return true;
    }

    return false;
}

/**
 * @brief CSceneManager::deleteShader 删除shader脚本
 * @param sharderid
 */
void CSceneManager::deleteShader(quint32 sharderid)
{
    if(sharderid > 0 || !isShaderExist(sharderid)) return;

    if(sharderid > 0)
    {
        QHash<QString,quint32>::iterator iter = m_sharderIds.begin();
        for(;iter != m_sharderIds.end();++iter)
        {
            if(iter.value() != sharderid)
                continue;

            glDeleteProgram(iter.value());
            m_sharderIds.erase(iter);
            break;
        }

        return;
    }

    QHash<QString,quint32>::iterator iter = m_sharderIds.begin();
    for(;iter != m_sharderIds.end();++iter)
    {
        glDeleteProgram(iter.value());
    }
    m_sharderIds.clear();
}

/**
 * @brief CSceneManager::useShader 使用shader脚本
 * @param shaderid
 */
void CSceneManager::useShader(quint32 shaderid)
{
    if(shaderid <= 0 || !isShaderExist(shaderid)) return;

    glUseProgram(shaderid);
}

/**
 * @brief CSceneManager::addNode 添加结点
 * @param node
 * @param position
 * @param direction 0:后面;1:前面
 * @return
 */
bool CSceneManager::addNode(CBaseNode *node,CBaseNode *position,int direction)
{
    if(isNodeExist(node))
        return false;

    node->setSceneManager(this);

    if(position)
    {
        int pos = m_nodes.indexOf(position);

        if(direction == 0)
        {
            m_nodes.insert(pos,node);
        }
        else
        {
            if(pos-1 > 0)
                m_nodes.insert(pos,node);
            else
                m_nodes.push_back(node);
        }

        return true;
    }

    if(direction == 0)
        m_nodes.push_back(node);
    else
        m_nodes.push_front(node);

    return true;
}

/**
 * @brief CSceneManager::deleteNode 删除结点
 * @param node
 */
void CSceneManager::deleteNode(CBaseNode *node)
{
    if(!isNodeExist(node))
        return;

    QList<CBaseNode*>::iterator iter = qFind(m_nodes.begin(),m_nodes.end(),node);
    if(iter != m_nodes.end())
    {
        delete (*iter);
        m_nodes.erase(iter);
    }
}

/**
 * @brief CSceneManager::removeNode 从管理器中清除结点但不删除
 * @param node
 */
void CSceneManager::removeNode(CBaseNode *node)
{
    if(!isNodeExist(node))
        return;

    QList<CBaseNode*>::iterator iter = qFind(m_nodes.begin(),m_nodes.end(),node);
    if(iter != m_nodes.end())
    {
        m_nodes.erase(iter);
    }
}

/**
 * @brief CSceneManager::deleteAllNodes 删除所有结点
 */
void CSceneManager::deleteAllNodes(void)
{
    QList<CBaseNode*>::iterator iter = m_nodes.begin();
    for(;iter != m_nodes.end();++iter)
        delete (*iter);

    m_nodes.clear();
}

/**
 * @brief CSceneManager::isNodeExist 检测指定结点是否存在
 * @param node
 * @return
 */
bool CSceneManager::isNodeExist(CBaseNode *node)
{
    if(node == NULL || m_nodes.empty())
        return false;

    QList<CBaseNode*>::iterator iter = qFind(m_nodes.begin(),m_nodes.end(),node);
    if(iter != m_nodes.end())
        return true;

    return false;
}

void CSceneManager::initializeGL()
{
    this->initializeOpenGLFunctions();

    glEnable(GL_DEPTH_TEST);

    initScene();
}

void CSceneManager::paintGL()
{
    /*清空颜色缓存，深度缓存，模板缓存*/
    //glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    drawScene();

    update();
}

void CSceneManager::resizeGL(int width, int height)
{
    /*获取设备像素比*/
    const qreal retinaScale = devicePixelRatio();
    //设置视口
    glViewport(0, 0, width * retinaScale, height * retinaScale);
}

/**
 * @brief CSceneManager::initAllNodes 初始所有的子结点
 */
void CSceneManager::initAllNodes(void)
{
    QList<CBaseNode*>::iterator iter = m_nodes.begin();
    for(;iter != m_nodes.end();++iter)
        (*iter)->init();
}

/**
 * @brief CSceneManager::drawAllNodes 绘制所有的子结点
 */
void CSceneManager::drawAllNodes(void)
{
    QList<CBaseNode*>::iterator iter = m_nodes.begin();
    for(;iter != m_nodes.end();++iter)
        (*iter)->draw();
}

/**
 * @brief CSceneManager::processAllNodesMouseEvent 处理所有子结点的鼠标事件
 * @param event
 */
bool CSceneManager::processAllNodesMouseEvent(QMouseEvent *event)
{
    QList<CBaseNode*>::iterator iter = m_nodes.begin();
    for(;iter != m_nodes.end();++iter)
        (*iter)->onProcessMouseEvent(event);

    return true;
}

/**
 * @brief CSceneManager::processAllNodesWheelEvent 处理所有子结点的滚轮事件
 * @param event
 */
void CSceneManager::processAllNodesWheelEvent(QWheelEvent *event)
{
    QList<CBaseNode*>::iterator iter = m_nodes.begin();
    for(;iter != m_nodes.end();++iter)
        (*iter)->onProcessWheelEvent(event);
}

/**
 * @brief CSceneManager::processAllNodesKeyEvent 处理所有子结点的键盘事件
 * @param event
 */
void CSceneManager::processAllNodesKeyEvent(QKeyEvent *event)
{
    QList<CBaseNode*>::iterator iter = m_nodes.begin();
    for(;iter != m_nodes.end();++iter)
        (*iter)->onProcessKeyEvent(event);
}

/**
 * @brief CSceneManager::initScene 创建初始化
 */
void CSceneManager::initScene(void)
{
    initAllNodes();
}

/**
 * @brief CSceneManager::drawScene 绘制
 */
void CSceneManager::drawScene(void)
{
    qint64 currentTime = QDateTime::currentSecsSinceEpoch();
    m_deltaTime = (float)(currentTime - m_lastTime);
    m_lastTime = currentTime;

    drawAllNodes();
}

bool CSceneManager::eventFilter(QObject *watched, QEvent *event)
{
    if(watched != this)
        return QOpenGLWidget::eventFilter(watched,event);

    switch (event->type())
    {
        case QEvent::MouseButtonPress:
        case QEvent::MouseButtonRelease:
        case QEvent::MouseMove:
        {
            QMouseEvent *pmouseevent = dynamic_cast<QMouseEvent*>(event);

            this->onProcessMouseEvent(pmouseevent);
        }
            break;
        case QEvent::Wheel:
        {
            QWheelEvent *pwheelevent = dynamic_cast<QWheelEvent*>(event);

            this->onProcessWheelEvent(pwheelevent);
        }
            break;
        case QEvent::KeyPress:
        case QEvent::KeyRelease:
        {
            QKeyEvent *pkeyevent = dynamic_cast<QKeyEvent*>(event);

            this->onProcessKeyEvent(pkeyevent);
        }
            break;
        default:
            break;
    }

    return QOpenGLWidget::eventFilter(watched,event);
}

/**
 * @brief onProcessMouseEvent 处理鼠标事件
 * @param event
 * @return
 */
bool CSceneManager::onProcessMouseEvent(QMouseEvent *event)
{
    mainCamera.onProcessMouseEvent(event);

    return processAllNodesMouseEvent(event);
}

/**
 * @brief CSceneManager::onProcessWheelEvent 处理鼠标滚轮事件
 * @param event
 */
void CSceneManager::onProcessWheelEvent(QWheelEvent *event)
{
    mainCamera.onProcessWheelEvent(event);

    processAllNodesWheelEvent(event);
}

/**
 * @brief CSceneManager::onProcessKeyEvent 处理键盘事件
 * @param event
 */
void CSceneManager::onProcessKeyEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_F12:
    {
        this->setFullscreen(!m_fullscreen);
        return;
    }
        break;
    default:
        break;
    }

    mainCamera.onProcessKeyEvent(event,m_deltaTime);

    processAllNodesKeyEvent(event);
}
